package channelService

import (
	"go-fox-edge-channel-opc-ua/channelEntity"
	"go-fox-edge-channel-opc-ua/channelEvent"
	"context"
	"encoding/json"
	"gitee.com/fierce_wolf/go-fox-edge-channel-common/channelStatus"
	"gitee.com/fierce_wolf/go-fox-edge-common/commLogger"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Json"
	"github.com/gopcua/opcua"
	"github.com/gopcua/opcua/ua"
	"net"
	"reflect"
	"sync"
	"time"
)

type OpcUaConnector struct {
	channelName2Client sync.Map
}

func (e *OpcUaConnector) Scheduler() {
	go e.connectOPC()
	go e.invalidOPC()
	go e.inspectOPC()
}

func (e *OpcUaConnector) connectOPC() {
	for {
		channelName2Entity := service.getChannelNames()
		for channelName := range channelName2Entity {
			val, ok := service.channelName2Entity.Load(channelName)
			if !ok {
				continue
			}
			entity := val.(*channelEntity.OpcUaEntity)

			// 检查：连接是否已经建立
			if e.hasConnect(entity.ChannelName) {
				continue
			}

			// 建立连接
			err := e.createConnect(entity)
			if err != nil {
				continue
			}

			channelStatus.UpdateParamStatus(entity.ChannelName, "connected", true)

			commLogger.Info("建立连接：" + entity.ChannelName + ", 连接信息->EndPoint=" + entity.EndPoint)
		}

		time.Sleep(1 * time.Second)
	}
}

func (e *OpcUaConnector) invalidOPC() {
	for {
		jsn := channelEvent.Invalid.Wait(1000)
		if jsn == "" {
			continue
		}

		entity := &channelEntity.OpcUaEntity{}
		err := json.Unmarshal([]byte(jsn), entity)
		if err != nil {
			continue
		}

		// 删除失效的连接
		e.deleteConnect(entity)
	}
}

func (e *OpcUaConnector) inspectOPC() {
	for {
		channelName2Entity := service.getChannelNames()
		for channelName := range channelName2Entity {
			val, ok := service.channelName2Entity.Load(channelName)
			if !ok {
				continue
			}
			entity := val.(*channelEntity.OpcUaEntity)

			// 检查：连接是否已经建立
			val, ok = e.channelName2Client.Load(entity.ChannelName)
			if !ok {
				continue
			}
			client := val.(*opcua.Client)

			// 检查：状态是否连接断开或者是连接关闭
			state := client.State()
			if !(state == opcua.Closed || state == opcua.Disconnected) {
				continue
			}

			commLogger.Info("连接异常：" + entity.ChannelName + ", 连接信息->EndPoint=" + entity.EndPoint)

			// 发出通知：失效掉该异常的连接
			channelEvent.Invalid.Notify(Json.BuildJson(entity))
		}

		time.Sleep(10 * time.Second)
	}
}

func (e *OpcUaConnector) isOpError(err error) bool {
	return reflect.TypeOf(err).Kind() == reflect.TypeOf(&net.OpError{}).Kind()
}

func (e *OpcUaConnector) hasConnect(channelName string) bool {
	// 检查：连接是否已经建立
	_, ok := e.channelName2Client.Load(channelName)
	if !ok {
		return false
	}

	return true
}

func (e *OpcUaConnector) createConnect(entity *channelEntity.OpcUaEntity) error {
	// 释放掉可能存在的旧连续信息
	e.channelName2Client.Delete(entity.ChannelName)

	// 建立连接
	ctx := context.Background()
	client, err := opcua.NewClient(entity.EndPoint, opcua.SecurityMode(ua.MessageSecurityModeNone))
	if err = client.Connect(ctx); err != nil {
		client.Close(ctx)
		return err
	}

	// 保存连接信息
	e.channelName2Client.Store(entity.ChannelName, client)

	return nil
}

func (e *OpcUaConnector) deleteConnect(entity *channelEntity.OpcUaEntity) error {
	// 释放掉可能存在的旧连续信息
	val, ok := e.channelName2Client.Load(entity.ChannelName)
	if ok {
		handler := val.(*opcua.Client)
		handler.Close(context.Background())

		e.channelName2Client.Delete(entity.ChannelName)
	}

	channelStatus.UpdateParamStatus(entity.ChannelName, "connected", false)

	commLogger.Info("连接断开：" + entity.ChannelName + ", 连接信息->Connect=" + entity.EndPoint)

	return nil
}
